﻿using Cairo;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FigureDraw.Graphic.Cairo
{
    public class CairoJPEGGraphic : CommonGraphic
    {
        private string filename;
        private ImageSurface img;

        private Context c;

        public CairoJPEGGraphic(string filename, MyPoint size)
        {
            this.filename = filename;
            img = new ImageSurface(Format.Rgb24, (int)size.X, (int)size.Y);
            c = new Context(img);  
        }

        override public void DrawLine(MyPoint p1, MyPoint p2, MyColorInfo strokeColor, double strokeWidth)
        {
            c.Color = ConvertToCairoColor(strokeColor);
            c.LineWidth = strokeWidth;

            c.MoveTo(p1.X, p1.Y);
            c.LineTo(p2.X, p2.Y);

            c.Stroke();
        }

        public override void DrawRectangle(MyPoint position, MyPoint size, MyColorInfo strokeColor, double strokeWidth, MyColorInfo brushColor)
        {
            c.Color = ConvertToCairoColor(strokeColor);
            c.LineWidth = strokeWidth;

            c.Rectangle(position.X, position.Y, size.X, size.Y);

            FillShape(brushColor);
            c.Stroke();
        }

        public override void DrawEllipse(MyPoint position, MyPoint size, MyColorInfo strokeColor, double strokeWidth, MyColorInfo brushColor)
        {
            double ratio = Math.Min(size.X, size.Y) / Math.Max(size.X, size.Y);

            double wScale = size.X >= size.Y ? 1 : ratio;
            double hScale = size.Y >= size.X ? 1 : ratio;
            PointD center = new PointD((position.X + size.X / 2) / wScale, (position.Y + size.Y / 2) / hScale);

            c.Color = ConvertToCairoColor(strokeColor);
            c.LineWidth = strokeWidth;

            c.Scale(wScale, hScale);
            c.Arc(center.X, center.Y, Math.Max(size.X, size.Y) / 2, 0, 2 * Math.PI);
            c.Scale(1 / wScale, 1 / hScale);

            FillShape(brushColor);
            c.Stroke();
        }

        public override void DrawText(MyPoint position, string text, double size, MyColorInfo strokeColor)
        {
            c.Color = ConvertToCairoColor(strokeColor);

            c.SelectFontFace("Tahoma", FontSlant.Normal, FontWeight.Bold);
            c.SetFontSize(size);
            c.MoveTo(position.X, position.Y + size);

            c.ShowText(text);

            c.Stroke();
        }

        public override void DrawCurve(MyColorInfo strokeColor, double strokeWidth, MyPoint[] points)
        {
            c.Color = ConvertToCairoColor(strokeColor);
            c.LineWidth = strokeWidth;

            for (int i = 0; i < points.Length; i += 3)
                c.CurveTo(points[0].X, points[0].Y, points[1].X, points[1].Y, points[2].X, points[2].Y);

            c.Stroke();
        }

        public override void DrawRoundedRectangle(MyPoint position, MyPoint size, MyColorInfo strokeColor, double strokeWidth, MyColorInfo brushColor)
        {
            double cornerRadius = 15;

            if ((cornerRadius > size.Y / 2) || (cornerRadius > size.X / 2))
                cornerRadius = Math.Min(size.Y / 2, size.X / 2);

            c.Color = ConvertToCairoColor(strokeColor);
            c.LineWidth = strokeWidth;

            c.MoveTo(position.X, position.Y + cornerRadius);
            c.Arc(position.X + cornerRadius, position.Y + cornerRadius, cornerRadius, Math.PI, -Math.PI / 2);
            c.LineTo(position.X + size.X - cornerRadius, position.Y);
            c.Arc(position.X + size.X - cornerRadius, position.Y + cornerRadius, cornerRadius, -Math.PI / 2, 0);
            c.LineTo(position.X + size.X, position.Y + size.Y - cornerRadius);
            c.Arc(position.X + size.X - cornerRadius, position.Y + size.Y - cornerRadius, cornerRadius, 0, Math.PI / 2);
            c.LineTo(position.X + cornerRadius, position.Y + size.Y);
            c.Arc(position.X + cornerRadius, position.Y + size.Y - cornerRadius, cornerRadius, Math.PI / 2, Math.PI);

            FillShape(brushColor);

            c.ClosePath();
            c.Stroke();
        }

        public override void DrawPolygon(MyColorInfo strokeColor, double strokeWidth, MyColorInfo brushColor, params MyPoint[] points)
        {
            c.Color = ConvertToCairoColor(strokeColor);
            c.LineWidth = strokeWidth;

            c.MoveTo(points[0].X, points[0].Y);

            for (int i = 1; i < points.Length; i++)
                c.LineTo(points[i].X, points[i].Y);

            c.ClosePath();

            FillShape(brushColor);

            c.Stroke();

        }

        private void FillShape(MyColorInfo brushColor)
        {
            if (brushColor != null)
            {
                c.Save();
                c.Color = ConvertToCairoColor(brushColor);
                c.FillPreserve();
                c.Restore();
            }
        }

        private Color ConvertToCairoColor(MyColorInfo color)
        {
            return new Color((double)color.R / 255, (double)color.G / 255, (double)color.B / 255);
        }

        override public void DrawPicture(List<MyShape> shapes)
        {
            base.DrawPicture(shapes);
            img.WriteToPng(filename);
            img.Finish();
        }
    }
}
